/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.diplomka.datalayer.daoimpl;

import cz.muni.fi.diplomka.datalayer.dao.MarchingArmyDao;
import cz.fi.muni.diplomka.common.Coordinates;
import cz.muni.fi.diplomka.datalayer.entity.MarchingArmyEntity;
import cz.fi.muni.diplomka.common.Squad;
import cz.fi.muni.diplomka.common.Unit;
import cz.fi.muni.diplomka.common.enumeration.MovementType;
import cz.fi.muni.diplomka.common.enumeration.UnitType;
import cz.muni.fi.diplomka.datalayer.util.DbConnector;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Jakub Kutil
 */
public class MarchingArmyDaoImpl implements MarchingArmyDao {

    private Connection con = null;
    private PreparedStatement ps = null;
    private ResultSet rs = null;

    public MarchingArmyDaoImpl() {
    }

    @Override
    public void addMarchingArmy(MarchingArmyEntity marchingArmyEntity) {
        if (marchingArmyEntity == null) {
            throw new IllegalArgumentException("MarchingArmyEntity can not be null");
        }
        try {

            con = DbConnector.getDBConnection();
            String insert = "INSERT INTO marching_army (owner_city_id, city_from, x_coordinate_to, y_coordinate_to, name, \"returning\", time_of_arrival, stolen_food, stolen_gold, stolen_stone, movement_type)"
                    + "VALUES (?,?,?,?,?,?,?,?,?,?,?)";
            ps = con.prepareStatement(insert);

            ps.setLong(1, marchingArmyEntity.getOwnerCityId());
            ps.setLong(2, marchingArmyEntity.getCityIdFrom());
            ps.setInt(3, marchingArmyEntity.getCoordinates().getX_coordinate());
            ps.setInt(4, marchingArmyEntity.getCoordinates().getY_coordinate());
            ps.setString(5, marchingArmyEntity.getName());
            ps.setBoolean(6, marchingArmyEntity.isReturning());
            ps.setTimestamp(7, marchingArmyEntity.getTimeOfArrival());
            ps.setInt(8, marchingArmyEntity.getStolenGold());
            ps.setInt(9, marchingArmyEntity.getStolenFood());
            ps.setInt(10, marchingArmyEntity.getStolenStone());
            ps.setString(11, marchingArmyEntity.getMovement().toString());

            ps.executeUpdate();

            rs = ps.getGeneratedKeys();
            rs.next();

            String getId = "SELECT max(id) FROM marching_army";

            ps = con.prepareStatement(getId);
            rs = ps.executeQuery();
            rs.next();
            Long id = rs.getLong(1);

            insert = "INSERT INTO marching_army_units (army_id, position, name, count, threshold)"
                    + "VALUES (?,?,?,?,?)";

            ps = con.prepareStatement(insert);

            for (Squad squad : marchingArmyEntity.getArmy().getSquads()) {
                ps.setLong(1, id);
                ps.setInt(2, squad.getPosition());
                ps.setString(3, squad.getUnit().getName().toString());
                ps.setInt(4, (int) squad.getCount());
                ps.setInt(5, (int) squad.getThreshold());

                ps.executeUpdate();
            }
        } catch (SQLException ex) {
            Logger.getLogger(MarchingArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
    }

    @Override
    public void editMarchingArmy(MarchingArmyEntity marchingArmyEntity) {
        if (marchingArmyEntity == null) {
            throw new IllegalArgumentException("MarchingArmyEntity can not be null");
        }
        try {
            con = DbConnector.getDBConnection();
            String update = "UPDATE marching_army SET owner_city_id=?, city_from=?, x_coordinate_to=?, y_coordinate_to=?, name=?, \"returning\"=?, time_of_arrival=?, stolen_food=?, stolen_gold=?, stolen_stone=?, movement_type=? WHERE id=?";

            ps = con.prepareStatement(update);

           ps.setLong(1, marchingArmyEntity.getOwnerCityId());
            ps.setLong(2, marchingArmyEntity.getCityIdFrom());
            ps.setInt(3, marchingArmyEntity.getCoordinates().getX_coordinate());
            ps.setInt(4, marchingArmyEntity.getCoordinates().getY_coordinate());
            ps.setString(5, marchingArmyEntity.getName());
            ps.setBoolean(6, marchingArmyEntity.isReturning());
            ps.setTimestamp(7, marchingArmyEntity.getTimeOfArrival());
            ps.setInt(8, marchingArmyEntity.getStolenGold());
            ps.setInt(9, marchingArmyEntity.getStolenFood());
            ps.setInt(10, marchingArmyEntity.getStolenStone());
            ps.setString(11, marchingArmyEntity.getMovement().toString());
            ps.setLong(12, marchingArmyEntity.getId());

            ps.executeUpdate();

            update = "UPDATE marching_army_units SET name=?, count=?, threshold=? WHERE army_id=? AND position=?";

            ps = con.prepareStatement(update);

            for (Squad squad : marchingArmyEntity.getArmy().getSquads()) {

                ps.setString(1, squad.getUnit().getName().toString());
                ps.setInt(2, (int) squad.getCount());
                ps.setInt(3, (int) squad.getThreshold());
                ps.setLong(4, marchingArmyEntity.getId());
                ps.setInt(5, squad.getPosition());

                ps.executeUpdate();
            }
        } catch (SQLException ex) {
            Logger.getLogger(MarchingArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
    }

    @Override
    public void deleteMarchingArmy(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("ID can not be null");
        }
        try {
            con = DbConnector.getDBConnection();
            String delete = "DELETE FROM marching_army_units WHERE army_id=?";

            ps = con.prepareStatement(delete);

            ps.setLong(1, id);

            ps.executeUpdate();

            delete = "DELETE FROM marching_army WHERE id=?";

            ps = con.prepareStatement(delete);

            ps.setLong(1, id);

            ps.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(MarchingArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
    }

    @Override
    public List<MarchingArmyEntity> getAllMarchingArmiesOfCity(Long cityId) {
        if (cityId == null) {
            throw new IllegalArgumentException("City ID cant be null");
        }
        List<MarchingArmyEntity> marchingArmyEntityList = new ArrayList<>();

        try {
            con = DbConnector.getDBConnection();
            String getArmiesInCity = "SELECT id, owner_city_id, city_from, x_coordinate_to, y_coordinate_to, marching_army.name AS army_name, \"returning\", "
                    + "stolen_food, stolen_gold, stolen_stone, movement_type, time_of_arrival, position, "
                    + "marching_army_units.name AS unit_name, count, threshold "
                    + "FROM marching_army INNER JOIN marching_army_units ON marching_army.id = marching_army_units.army_id "
                    + "WHERE owner_city_id=?";

            ps = con.prepareStatement(getArmiesInCity);
            ps.setLong(1, cityId);

            rs = ps.executeQuery();
            Map<Integer, MarchingArmyEntity> armyMap = new HashMap();
            while (rs.next()) {
                if (!armyMap.containsKey(rs.getInt("id"))) {

                    MarchingArmyEntity marchingArmyEntity = new MarchingArmyEntity();

                    marchingArmyEntity.setId(rs.getLong("id"));
                    marchingArmyEntity.setOwnerCityId(rs.getLong("owner_city_id"));
                    marchingArmyEntity.setCityIdFrom(rs.getLong("city_from"));
                    Coordinates c = new Coordinates();
                    c.setX_coordinate(rs.getInt("x_coordinate_to"));
                    c.setY_coordinate(rs.getInt("y_coordinate_to"));
                    marchingArmyEntity.setCoordinates(c);
                    marchingArmyEntity.setName(rs.getString("army_name"));
                    marchingArmyEntity.setReturning(rs.getBoolean("returning"));
                    marchingArmyEntity.setStolenFood(rs.getInt("stolen_food"));
                    marchingArmyEntity.setStolenGold(rs.getInt("stolen_gold"));
                    marchingArmyEntity.setStolenStone(rs.getInt("stolen_stone"));
                    marchingArmyEntity.setMovement(MovementType.valueOf(rs.getString("movement_type")));
                    marchingArmyEntity.setTimeOfArrival(rs.getTimestamp("time_of_arrival"));

                    armyMap.put(rs.getInt("id"), marchingArmyEntity);
                }
                Unit unitEntity = new Unit();
                unitEntity.setName(UnitType.valueOf(rs.getString("unit_name")));

                Squad squad = new Squad();
                squad.setPosition(rs.getInt("position"));
                squad.setUnit(unitEntity);
                squad.setCount(rs.getInt("count"));
                squad.setThreshold(rs.getInt("threshold"));

                armyMap.get(rs.getInt("id")).getArmy().getSquads().add(squad);
            }

            for (MarchingArmyEntity marchingArmyEntity : armyMap.values()) {
                marchingArmyEntityList.add(marchingArmyEntity);
            }
        } catch (SQLException ex) {
            Logger.getLogger(MarchingArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
        return marchingArmyEntityList;
    }
    
    @Override
    public List<MarchingArmyEntity> getAllMarchingArmies() {

        List<MarchingArmyEntity> marchingArmyEntityList = new ArrayList<>();

        try {
            con = DbConnector.getDBConnection();
            String getArmiesInCity = "SELECT id, owner_city_id, city_from, x_coordinate_to, y_coordinate_to, marching_army.name AS army_name, \"returning\", "
                    + "stolen_food, stolen_gold, stolen_stone, movement_type, time_of_arrival, position, "
                    + "marching_army_units.name AS unit_name, count, threshold "
                    + "FROM marching_army INNER JOIN marching_army_units ON marching_army.id = marching_army_units.army_id ";

            ps = con.prepareStatement(getArmiesInCity);

            rs = ps.executeQuery();
            Map<Integer, MarchingArmyEntity> armyMap = new HashMap();
            while (rs.next()) {
                if (!armyMap.containsKey(rs.getInt("id"))) {

                    MarchingArmyEntity marchingArmyEntity = new MarchingArmyEntity();

                    marchingArmyEntity.setId(rs.getLong("id"));
                    marchingArmyEntity.setOwnerCityId(rs.getLong("owner_city_id"));
                    marchingArmyEntity.setCityIdFrom(rs.getLong("city_from"));
                    Coordinates c = new Coordinates();
                    c.setX_coordinate(rs.getInt("x_coordinate_to"));
                    c.setY_coordinate(rs.getInt("y_coordinate_to"));
                    marchingArmyEntity.setCoordinates(c);
                    marchingArmyEntity.setName(rs.getString("army_name"));
                    marchingArmyEntity.setReturning(rs.getBoolean("returning"));
                    marchingArmyEntity.setStolenFood(rs.getInt("stolen_food"));
                    marchingArmyEntity.setStolenGold(rs.getInt("stolen_gold"));
                    marchingArmyEntity.setStolenStone(rs.getInt("stolen_stone"));
                    marchingArmyEntity.setMovement(MovementType.valueOf(rs.getString("movement_type")));
                    marchingArmyEntity.setTimeOfArrival(rs.getTimestamp("time_of_arrival"));

                    armyMap.put(rs.getInt("id"), marchingArmyEntity);
                }
                Unit unitEntity = new Unit();
                unitEntity.setName(UnitType.valueOf(rs.getString("unit_name")));

                Squad squad = new Squad();
                squad.setPosition(rs.getInt("position"));
                squad.setUnit(unitEntity);
                squad.setCount(rs.getInt("count"));
                squad.setThreshold(rs.getInt("threshold"));

                armyMap.get(rs.getInt("id")).getArmy().getSquads().add(squad);
            }

            for (MarchingArmyEntity marchingArmyEntity : armyMap.values()) {
                marchingArmyEntityList.add(marchingArmyEntity);
            }
        } catch (SQLException ex) {
            Logger.getLogger(MarchingArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
        return marchingArmyEntityList;
    }
}
